<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html><head><title>Programming in Lua : 23.3</title>
<link rel="stylesheet" type="text/css" href="pil.css">
</head>
<body>
<p class="warning">
<A HREF="contents.html"><IMG TITLE="Programming in Lua (first edition)" SRC="capa.jpg" ALT="" ALIGN="left"></A>This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.<BR>The third edition targets Lua 5.2 and is available at <A HREF="http://www.amazon.com/exec/obidos/ASIN/859037985X/theprogrammil3-20">Amazon</A> and other bookstores.<BR>By buying the book, you also help to <A HREF="../donations.html">support the Lua project</A>.
</p>
<table width="100%" class="nav">
<tr>
<td width="10%" align="left"><a href="23.2.html"><img border="0" src="left.png" alt="Previous"></a></td>
<td width="80%" align="center"><a href="contents.html"><font face="Helvetica,Arial,sanserif">
<font color="gray">Programming in </font><font color="blue"> Lua</font>
</font></a></td>
<td width="10%" align="right"><a href="24.html"><img border="0" src="right.png" alt="Next"></a></td>
</tr>
<tr>
<td width="10%" align="left"></td>
<td width="80%" align="center"><a href="contents.html#P3">Part III. The Standard Libraries</a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<a href="contents.html#23">Chapter 23. The Debug Library</a></td>
<td width="10%" align="right"></td></tr>
</table>
<hr/>
<p><h2>23.3 &ndash; Profiles</h2>

<p>Despite its name,
the debug library is useful for tasks other than debugging.
A common such task is profiling.
For a profile with timing,
it is better to use the C interface:
The overhead of a Lua call for each hook is too high
and usually invalidates any measure.
However, for counting profiles,
Lua code does a decent job.
In this section, we will develop a rudimentary profiler,
which lists the number of times that each function in the
program is called in a run.

<p>The main data structure of our program is a table that
associates functions to their call counters
and a table that associates functions to their names.
The indices to these tables are the functions themselves.
<pre>
    local Counters = {}
    local Names = {}
</pre>
We could retrieve the name data after the profiling,
but remember that we get better results if we get the name of a function
while it is active,
because then Lua can look at the code that is calling the function
to find its name.

<p>Now we define the hook function.
Its job is to get the function being called and increment the
corresponding counter;
it also collects the function name:
<pre>
    local function hook ()
      local f = debug.getinfo(2, "f").func
      if Counters[f] == nil then    -- first time `f' is called?
        Counters[f] = 1
        Names[f] = debug.getinfo(2, "Sn")
      else  -- only increment the counter
        Counters[f] = Counters[f] + 1
      end
    end
</pre>
The next step is to run the program with this hook.
We will assume that the main chunk of the program is in a file
and that the user gives this file name as an argument to the
profiler:
<pre>
    prompt> lua profiler main-prog
</pre>
With this scheme, we get the file name in <code>arg[1]</code>,
turn on the hook, and run the file:
<pre>
    local f = assert(loadfile(arg[1]))
    debug.sethook(hook, "c")  -- turn on the hook
    f()   -- run the main program
    debug.sethook()   -- turn off the hook
</pre>
The last step is to show the results.
The next function produces a name for a function.
Because function names in Lua are so uncertain,
we add to each function its location,
given as a pair <em>file:line</em>.
If a function has no name,
then we use only its location.
If a function is a C function,
we use only its name (it has no location).
<pre>
    function getname (func)
      local n = Names[func]
      if n.what == "C" then
        return n.name
      end
      local loc = string.format("[%s]:%s",
                                n.short_src, n.linedefined)
      if n.namewhat ~= "" then
        return string.format("%s (%s)", loc, n.name)
      else
        return string.format("%s", loc)
      end
    end
</pre>
Finally, we print each function with its counter:
<pre>
    for func, count in pairs(Counters) do
      print(getname(func), count)
    end
</pre>

<p>If we apply our profiler to the <code>markov</code> example
that we developed in <a href="10.2.html#Markov">Section 10.2</a>,
we get a result like this:
<pre>
    [markov.lua]:4 884723
    write   10000
    [markov.lua]:0 (f)     1
    read    31103
    sub     884722
    [markov.lua]:1 (allwords)      1
    [markov.lua]:20 (prefix)       894723
    find    915824
    [markov.lua]:26 (insert)       884723
    random  10000
    sethook 1
    insert  884723
</pre>
That means that the anonymous function at line 4
(which is the iterator function defined inside <code>allwords</code>)
was called 884,723 times,
<code>write</code> (<code>io.write</code>) was called 10,000 times,
and so on.

<p>There are several improvements that you can make to this profiler,
such as to sort the output,
to print better function names,
and to improve the output format.
Nevertheless, this basic profiler is already useful as it is
and can be used as a base for more advanced tools.

<p>
<a name="API"></a>


<p>

<p>
<hr/>
<table width="100%" class="nav">
<tr valign="top">
<td width="90%" align="left">
<small>
  Copyright &copy; 2003&ndash;2004 Roberto Ierusalimschy.  All rights reserved.
</small>
</td>
<td width="10%" align="right"><a href="24.html"><img border="0" src="right.png" alt="Next"></a></td>
</tr>
</table>


</body></html>

